import java.awt.AlphaComposite;
import java.awt.Color;
import java.awt.Graphics2D;
import java.awt.geom.Line2D;
import java.awt.image.BufferedImage;
import java.io.ByteArrayOutputStream;
import java.io.DataInputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.io.PrintWriter;
import java.util.List;

import javax.activation.MimetypesFileTypeMap;
import javax.imageio.IIOImage;
import javax.imageio.ImageIO;
import javax.imageio.ImageWriteParam;
import javax.imageio.ImageWriter;
import javax.imageio.plugins.jpeg.JPEGImageWriteParam;
import javax.imageio.stream.ImageOutputStream;
import javax.servlet.ServletException;
import javax.servlet.ServletOutputStream;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;

import org.apache.commons.fileupload.FileItem;
import org.apache.commons.fileupload.FileUploadException;
import org.apache.commons.fileupload.disk.DiskFileItemFactory;
import org.apache.commons.fileupload.servlet.ServletFileUpload;
import org.imgscalr.Scalr;
import org.json.JSONArray;
import org.json.JSONObject;

/**
 * Servlet implementation class UploadServlet
 */
@WebServlet("/UploadServlet")
public class UploadServlet extends HttpServlet {

	private static final long serialVersionUID = 42L;
	
	/**
	 * @see HttpServlet#doGet(HttpServletRequest request, HttpServletResponse
	 *      response)
	 * 
	 */
	@Override
	protected void doGet(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {
	}

	/**
	 * @see HttpServlet#doPost(HttpServletRequest request, HttpServletResponse
	 *      response)
	 * 
	 */
	@SuppressWarnings("unchecked")
	@Override
	protected void doPost(HttpServletRequest request,
			HttpServletResponse response) throws ServletException, IOException {

		if (!ServletFileUpload.isMultipartContent(request)) {
			throw new IllegalArgumentException(
					"Request is not multipart, please 'multipart/form-data' enctype for your form.");
		}

		ServletFileUpload uploadHandler = new ServletFileUpload(
				new DiskFileItemFactory());
		PrintWriter writer = response.getWriter();
		response.setContentType("application/json");
		JSONArray json = new JSONArray();
		try {
			List<FileItem> items = uploadHandler.parseRequest(request);
			for (FileItem item : items) {
				if (!item.isFormField()) {
					File file = new File(request.getServletContext()
							.getRealPath("/") + "upload/audio", item.getName());
					item.write(file);
					JSONObject jsono = new JSONObject();
					jsono.put("name", item.getName());
					jsono.put("size", item.getSize());
					jsono.put("url", "UploadServlet?getfile=" + item.getName());
					jsono.put("thumbnail_url",
							"UploadServlet?getthumb=" + item.getName());
					jsono.put("delete_url",
							"UploadServlet?delfile=" + item.getName());
					jsono.put("delete_type", "GET");
					writeWaveform(file, new File(file.getAbsolutePath()
							+ ".png"), jsono);
		    		jsono.put("waveform", "upload/audio/" + item.getName() + ".jpg");
					json.put(jsono);
					System.out.println(json.toString());
				}
			}
		} catch (FileUploadException e) {
			throw new RuntimeException(e);
		} catch (Exception e) {
			throw new RuntimeException(e);
		} finally {
			writer.write(json.toString());
			writer.close();
		}

	}

	private void writeWaveform(File audioFile, File outFile, JSONObject jsono)
    {
    	try {
    		final AudioFileFormat format = AudioSystem.getAudioFileFormat(audioFile);
    		final AudioFileFormat.Type type = format.getType();
    		if (!AudioSystem.isFileTypeSupported(type)) {
    			System.err.println("filetype not supported: " + type.getClass().getSimpleName());
    		}
    		AudioInputStream audioInputStream = AudioSystem.getAudioInputStream(audioFile);
    		int numChannels = audioInputStream.getFormat().getChannels();
    		int frameSize = audioInputStream.getFormat().getFrameSize();
    		long frameLength = audioInputStream.getFrameLength();
    		float sampleRate = audioInputStream.getFormat().getSampleRate();
    		int sampleSize = audioInputStream.getFormat().getSampleSizeInBits();
    		jsono.put("num_channels", numChannels);
    		jsono.put("frame_size", frameSize);
    		jsono.put("frame_length", frameLength);
    		jsono.put("sample_rate", sampleRate);    		
    		jsono.put("sample_size", sampleSize);
    		int width = 1680;
    		int height = 1050;
    		long numBytes = frameLength * frameSize;
    		long numSamples = numBytes / (sampleSize/8);
    		BufferedImage bi = new BufferedImage(width, height, BufferedImage.TYPE_INT_ARGB);
    		Graphics2D g = (Graphics2D)bi.getGraphics();
    		int buf, bufOld = 0;
    		int maxSize = (int) Math.pow(2, sampleSize);
    		
    		int pixelBuffer = 80;    		
    		int yMax = height - pixelBuffer;
    		int yMin = pixelBuffer;
    		
//    		g.setColor(new Color(255, 255, 255, 0));
    		g.setComposite(AlphaComposite.Clear);
    		g.fillRect(0, 0, width, height);
    		
    		for (int i = 0; i < width; i++)
    		{
    			g.setComposite(AlphaComposite.Src);
    			g.setColor(Color.BLUE);
    			buf = audioInputStream.read();
    			if (i > 0)
    			{
    				g.draw(new Line2D.Double(i - 1, yMin + ((double)bufOld/maxSize)*(yMax - yMin), 
    						i, yMin + ((double)buf/maxSize)*(yMax - yMin)));
    			}
    			audioInputStream.skip(numBytes / width);
    			bufOld = buf;
    		}
    		audioInputStream.close();
    		g.dispose();
    		saveToFile(bi, outFile);
    	} catch (Exception e) {
    		System.out.println("Couldn't open stream");
    		e.printStackTrace();
    	}
    }

	private void saveToFile(BufferedImage img, File file) {
		ImageWriter writer = null;
		java.util.Iterator<ImageWriter> iter = ImageIO.getImageWritersByFormatName("png");
		
		if (iter.hasNext()) {
			writer = iter.next();
		}

		ImageOutputStream ios = null;
		try {
			ios = ImageIO.createImageOutputStream(file);
		} catch (IOException e) {
			System.out.println("Bad IO error");
		}

		writer.setOutput(ios);
		ImageWriteParam param = new JPEGImageWriteParam(
				java.util.Locale.getDefault());
		param.setCompressionMode(ImageWriteParam.MODE_EXPLICIT);
		param.setCompressionQuality(0.98f);

		try {
			writer.write(null, new IIOImage(img, null, null), param);
			ios.close();
		} catch (IOException e) {
			System.out.println("Writer cant write");
		}
	}
}